package com.example.petplanet.service;


import com.example.petplanet.domain.Comment;
import com.example.petplanet.domain.Content;
import com.example.petplanet.domain.LikeComment;
import com.example.petplanet.domain.User;
import com.example.petplanet.mapper.CommentDao;
import com.example.petplanet.mapper.ContentDao;
import com.example.petplanet.mapper.LikeCommentDao;
import com.example.petplanet.result.Result;
import com.example.petplanet.util.TLUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class CommentService {
    private final CommentDao commentDao;
    private final ContentDao contentDao;
    private final ShareService shareService;
    private final StringRedisTemplate stringRedisTemplate;
    private final LikeCommentDao likeCommentDao;


    @Autowired
    private RedissonClient redissonClient;

    private final String SYNC_LOCK = "isSyncing";

    @Autowired
    CommentService(ContentDao contentDao, CommentDao commentDao, ShareService shareService, StringRedisTemplate stringRedisTemplate, LikeCommentDao likeCommentDao){
        this.commentDao=commentDao;
        this.contentDao=contentDao;
        this.shareService = shareService;
        this.stringRedisTemplate = stringRedisTemplate;
        this.likeCommentDao = likeCommentDao;
    }
    public Result<Object> getCommentFromContent(Long contentId){
        if (contentDao.contentIsNotExist(contentId)) return Result.error("该内容已被删除");
        List<Comment> commentFromContent = commentDao.getCommentFromContent(contentId);
        commentFromContent=updateCommentsGoodFromMysql(commentFromContent);
        return Result.success(commentFromContent);
    }

    public Result<Object> publishComment(String comment,Long contentId,Long replyId,Long parentId){
        if(contentDao.contentIsNotExist(contentId)) return Result.error("该内容已被删除");
        Comment newComment = new Comment();
        newComment.setUserId(TLUtil.getUserId());
        newComment.setContentId(contentId);
        newComment.setComment(comment);
        newComment.setReplyId(replyId);
        newComment.setParentId(parentId);
        newComment.setPublish(LocalDateTime.now());
        if(replyId!=0 && commentDao.selectCommentId(replyId)==null) return Result.error("要回复的评论不存在");
        if(parentId !=0 && commentDao.selectCommentId(parentId)==null) return Result.error("无此父类评论");
        if (commentDao.publishComment(newComment)==0) return Result.error("评论失败");
        return Result.success(newComment);
    }


    @Transactional
    public Result<Object> deleteMyComment(Long commentId){
        // 检查是否处于禁止操作时间
        if (shareService.isForbiddenDelTime()) {
            return Result.error("当前处于禁止操作时间，请等待至少1分钟后再尝试");
        }
        if(shareService.isSyncLockCheckTime()){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return Result.error("删除操作异常: " + e.getMessage());
            }
            RLock syncLock = redissonClient.getLock(SYNC_LOCK);
            if (syncLock.isLocked()) {
                return Result.error("同步操作正在进行，删除操作失败");
            }
        }
        try {
            Comment comment = commentDao.selectCommentId(commentId);
            if(comment == null) return Result.error("删除失败，评论不存在");
            //commentId集合，点赞关系集合
            Set<Long> operateComments = new HashSet<>();
            List<LikeComment> likeComments=new ArrayList<>();
            try{
                //添加子评论
                if(comment.getParentId()==0 && comment.getReplyId()==0){
                    operateComments=commentDao.selectChildComments(commentId);
                    //mysql删除子评论
                    commentDao.deleteComments(operateComments);
                }
                operateComments.add(commentId);
                //获取点赞关系集合
                likeComments=likeCommentDao.selectLikeComByIds(operateComments);
                //mysql删除父评论
                if(commentDao.deleteMyComment(TLUtil.getUserId(), commentId) == 0) {
                    return Result.error(("数据库删除失败"));
                }
            }catch (Exception e){
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.error("删除失败: "+e.getMessage());
            }
            //redis同步,包括未同步到mysql的数据
            shareService.deleteCommentRedis(likeComments,operateComments);
            return Result.success();
        }catch (Exception e) {
            return Result.error("删除操作异常: " + e.getMessage());
        }
    }

    public Result<Object> getCommentById(Long commentId) {
        Comment comment = commentDao.selectCommentId(commentId);
        if(comment == null) return Result.error("评论不存在");
        // 构造Redis中的键
        String key = "app:likeCount:comment:" + comment.getCommentId();
        // 检查Redis中是否存在该键
        Boolean exists = stringRedisTemplate.hasKey(key);
        if(exists){
            Long goodCount = Long.parseLong(stringRedisTemplate.opsForValue().get(key));
            comment.setGood(goodCount);
        }
        return Result.success(comment);
    }

    public Result<Object> likeComment(Long commentId) {
        return LikeOrCancelComment(commentId,true);
    }

    public Result<Object> cancelLikeComment(Long commentId) {
        return LikeOrCancelComment(commentId,false);
    }

    public Result<Object> LikeOrCancelComment(Long commentId,boolean isLike){
        Comment comment = commentDao.selectCommentId(commentId);
        if(comment == null) return Result.error("评论不存在");
        Long userId =TLUtil.getUserId();
        User user=TLUtil.getUser();
        // 点赞或取消点赞
        boolean success = isLike ? user.getLikeComments().add(commentId) : user.getLikeComments().remove(commentId);
        if (!success) {
            return isLike ? Result.error("您已点赞过") : Result.error("还未点赞");
        }
        // 更新用户点赞序列
        shareService.updateUserRedis(user);
        String key = "app:user:" + userId.toString();
        stringRedisTemplate.expire(key, 10, TimeUnit.DAYS);
        // 点赞关系
        String commentKey = "app:like:comment:" + userId + ":" + commentId;
        boolean updated = shareService.updateKeyValue(commentKey, isLike ? "true" : "false", 7, TimeUnit.HOURS);
        if (!updated) {
            return isLike ? Result.error("已点赞") : Result.error("已取消点赞");
        }
        // 更新Redis点赞数
        updateCommentLikeCount(commentId,comment, isLike ? 1L : -1L, 7, TimeUnit.HOURS);
        return Result.success();
    }


    //可复用
    private void updateCommentLikeCount(Long commentId,Comment comment,Long value,long timeout,TimeUnit timeUnit){
        //没有key，新增，有key加value
        String key="app:likeCount:comment:"+commentId.toString();
        Boolean exists = stringRedisTemplate.hasKey(key);
        if (!exists) {
            // 如果键不存在，直接设置值
            Long good=comment.getGood();
            good=good+value;
            stringRedisTemplate.opsForValue().set(key,
                    good.toString(),
                    timeout,
                    timeUnit);
        }else {
            // 如果键存在，使用 INCRBY 命令更新当前值
            stringRedisTemplate.opsForValue().increment(key, value);
            stringRedisTemplate.expire(key,timeout,timeUnit);
        }
    }


    public List<Comment> updateCommentsGoodFromMysql(List<Comment> comments){
        for (Comment comment : comments) {
            // 构造Redis中的键
            String key = "app:likeCount:comment:" + comment.getCommentId();
            // 检查Redis中是否存在该键
            Boolean exists = stringRedisTemplate.hasKey(key);
            if(exists){
                Long goodCount = Long.parseLong(stringRedisTemplate.opsForValue().get(key));
                comment.setGood(goodCount);
            }
        }
        return comments;
    }
}

